package com.pa165.languageschoolpresentation;

import com.pa165.languageschoolpersistence.Exceptions.ServiceFailureException;
import com.pa165.languageschoolservice.DTO.CourseDTO;
import com.pa165.languageschoolservice.DTO.LectorDTO;
import com.pa165.languageschoolservice.DTO.LectureDTO;
import com.pa165.languageschoolservice.DTO.StudentDTO;
import com.pa165.languageschoolservice.service.CourseService;
import com.pa165.languageschoolservice.service.LectorService;
import com.pa165.languageschoolservice.service.LectureService;
import com.pa165.languageschoolservice.service.StudentService;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.Before;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Tomas Hruby
 * 
 * Action bean for lecture handling.
 */
@UrlBinding("/lectures/{$event}/{lectureDTO.id}")
public class LectureActionBean implements ActionBean {

    final static Logger log = LoggerFactory.getLogger(LectureActionBean.class);
    private ActionBeanContext context;
    private Long lectorId;
    private Long courseId;
    private Long studentId;
    private String startString;
    private String endString;
    @SpringBean
    protected LectureService lectureService;
    @SpringBean
    protected LectorService lectorService;
    @SpringBean
    protected CourseService courseService;
    @SpringBean
    protected StudentService studentService;
    @ValidateNestedProperties(value = {
        @Validate(on = {"saveAdd", "saveEdit"}, field = "name", required = true),
        @Validate(on = {"saveAdd", "saveEdit"}, field = "roomNumber", required = true)
    })
    private LectureDTO lectureDTO;
    public static String FORMATSTRING = "yyyy-MM-dd H:mm";
    private SimpleDateFormat sdfSource = new SimpleDateFormat(FORMATSTRING);

    public LectureService getLectureService() {
        return lectureService;
    }

    public void setLectureService(LectureService lectureService) {
        this.lectureService = lectureService;
    }

    public SimpleDateFormat getSdfSource() {
        return sdfSource;
    }

    public void setSdfSource(SimpleDateFormat sdfSource) {
        this.sdfSource = sdfSource;
    }

    public LectorService getLectorService() {
        return lectorService;
    }

    public void setLectorService(LectorService lectorService) {
        this.lectorService = lectorService;
    }

    public CourseService getCourseService() {
        return courseService;
    }

    public void setCourseService(CourseService courseService) {
        this.courseService = courseService;
    }

    public StudentService getStudentService() {
        return studentService;
    }

    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }

    @DefaultHandler
    public Resolution all() {
        log.debug("all()");
        return new ForwardResolution("/lecture/lecture.jsp");
    }

    public Resolution add() {
        // Log
        log.debug("add() lecture={}", lectureDTO);

        return new ForwardResolution("/lecture/lectureAdd.jsp");
    }

    public Resolution saveAdd() throws ServiceFailureException{
        // Log
        log.debug("add() lecture={}", lectureDTO);
        CourseDTO courseDTO;
        LectorDTO lectorDTO;
        try {
            lectorDTO = lectorService.get(lectorId);
        } catch ( ServiceFailureException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("lector", new LocalizableError("lector.empty"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        try {
            courseDTO = courseService.get(courseId);
        } catch ( ServiceFailureException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("course", new LocalizableError("course.empty"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        lectureDTO.setLector(lectorDTO);
        lectureDTO.setCourse(courseDTO);
        try {
            lectureDTO.setStartTime(parseDate(startString));
            lectureDTO.setEndTime(parseDate(endString));
        } catch (ParseException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("lecture", new LocalizableError("lecture.dateFormat"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }

        lectureService.add(lectureDTO);

        return new RedirectResolution(this.getClass(), "all");
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"edit", "saveEdit", "delete", "showStudents"})
    public void loadLectureFromDatabase() throws ServiceFailureException{
        String ids = context.getRequest().getParameter("lectureDTO.id");
        if (ids == null) {
            return;
        }
        lectureDTO = lectureService.get(Long.parseLong(ids));

        lectorId = lectureDTO.getLector().getId();
        courseId = lectureDTO.getCourse().getId();

        startString = sdfSource.format(lectureDTO.getStartTime());
        endString = sdfSource.format(lectureDTO.getEndTime());
    }

    public Resolution edit() {
        // Log
        log.debug("edit() lecture={}", lectureDTO);

        return new ForwardResolution("/lecture/lectureEdit.jsp");
    }

    public Resolution saveEdit() throws ServiceFailureException{
        CourseDTO courseDTO;
        LectorDTO lectorDTO;
        try {
            lectorDTO = lectorService.get(lectorId);
        } catch ( ServiceFailureException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("lector", new LocalizableError("lector.empty"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        try {
            courseDTO = courseService.get(courseId);
        } catch ( ServiceFailureException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("course", new LocalizableError("course.empty"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }
        lectureDTO.setLector(lectorDTO);
        lectureDTO.setCourse(courseDTO);
        try {
            lectureDTO.setStartTime(parseDate(startString));
            lectureDTO.setEndTime(parseDate(endString));
        } catch (ParseException e) {
            ValidationErrors errors = new ValidationErrors();
            errors.add("lecture", new LocalizableError("lecture.dateFormat"));
            getContext().setValidationErrors(errors);
            return getContext().getSourcePageResolution();
        }

        // Log
        log.debug("edit() lecture={}", lectureDTO);
        lectureService.modify(lectureDTO);
        return new RedirectResolution(this.getClass(), "all");
    }

    public Resolution addStudent() throws ServiceFailureException{
        if (lectureDTO.getId() == null) {
        } else {
            studentService.enrollStudentToLecture(lectureDTO, studentService.get(studentId));
        }

        return new RedirectResolution("/lecture/lectureEdit.jsp");
    }

    public Resolution delete() throws ServiceFailureException{
        log.debug("delete({})", lectureDTO.getId());
        lectureService.remove(lectureDTO);
        return new RedirectResolution(this.getClass(), "all");
    }

    public List<LectureDTO> getLectures() {
        return lectureService.getAll();
    }

    public Resolution showStudents() {
        log.debug("showStudents()");
        return new ForwardResolution("/lecture/lectureStudents.jsp");
    }

    public List<StudentDTO> getStudentsInLecture() throws ServiceFailureException {
        log.debug("getLectures() studentDTO={}", lectureDTO);
        return studentService.findByLecture(lectureDTO);
    }

    public Date parseDate(String input) throws ParseException {

        Date date = getSdfSource().parse(input);
        return date;
    }

    public LectureDTO getLectureDTO() {
        return lectureDTO;
    }

    public void setLectureDTO(LectureDTO lectureDTO) {
        this.lectureDTO = lectureDTO;
    }

    public List<CourseDTO> getCourses() {
        return courseService.getAll();
    }

    public List<LectorDTO> getLectors() {
        return lectorService.getAll();
    }

    public List<StudentDTO> getStudents() throws ServiceFailureException{
        return studentService.getAll();
    }

    public Long getLectorId() {
        return lectorId;
    }

    public void setLectorId(Long lectorId) {
        this.lectorId = lectorId;
    }

    public Long getCourseId() {
        return courseId;
    }

    public void setCourseId(Long courseId) {
        this.courseId = courseId;
    }

    public Long getStudentId() {
        return studentId;
    }

    public void setStudentId(Long studentId) {
        this.studentId = studentId;
    }

    public String getStartString() {
        return startString;
    }

    public void setStartString(String startString) {
        this.startString = startString;
    }

    public String getEndString() {
        return endString;
    }

    public void setEndString(String endString) {
        this.endString = endString;
    }

    @Override
    public void setContext(ActionBeanContext context) {
        this.context = context;
    }

    @Override
    public ActionBeanContext getContext() {
        return context;
    }
}